package com.atguigu.yygh.order.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.atguigu.yygh.common.exception.YyghException;


import com.atguigu.yygh.enums.OrderStatusEnum;
import com.atguigu.yygh.hosp.client.HospitalFeignClient;
import com.atguigu.yygh.model.order.OrderInfo;
import com.atguigu.yygh.model.user.Patient;
import com.atguigu.yygh.mq.pojo.MqConst;
import com.atguigu.yygh.mq.service.RabbitService;
import com.atguigu.yygh.order.mapper.OrderMapper;
import com.atguigu.yygh.order.service.OrderService;
import com.atguigu.yygh.order.service.RefundService;
import com.atguigu.yygh.order.utils.HttpRequestHelper;

import com.atguigu.yygh.user.client.PatientFeignClient;
import com.atguigu.yygh.vo.hosp.ScheduleOrderVo;
import com.atguigu.yygh.order.vo.OrderMqVo;
import com.atguigu.yygh.vo.msm.MsmVo;
import com.atguigu.yygh.vo.order.OrderQueryVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @description: TODO
 * @author: 化一帆
 * @date: 2022/12/8 18:26
 * @version: v1.0
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderInfo> implements OrderService {

    @Autowired
    private PatientFeignClient patientFeignClient;

    @Autowired
    private HospitalFeignClient hospitalFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RefundService refundService;


    /**
     * @description: 生成挂号订单，返回值为订单的id
     * @author 化一帆
     * @date 2022/12/8 18:42
     */
    @Override
    public Long saveOrder(String scheduleId, Long patientId) {

        //根据就诊人的id得到数据,再根据排班id得到信息，最后将数据添加到数据库中
        // 加完数据库之后，去调用医院端的接口，在医院那边做订单的生成
        //医院接口那边会返回数据，我们根据返回数据来更新订单表中的内容

        //1.获取就诊人的信息
        Patient patient = patientFeignClient.getPatientOrder(patientId);

        //2.获取排班的相关信息
        ScheduleOrderVo scheduleOrderVo = hospitalFeignClient.getScheduleOrderVo(scheduleId);


        //3.设置调用医院端的接口需要的参数，将参数封装到map集合中
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("hoscode", scheduleOrderVo.getHoscode());
        paramMap.put("depcode", scheduleOrderVo.getDepcode());
        paramMap.put("hosScheduleId", scheduleOrderVo.getHosScheduleId());
        paramMap.put("reserveDate", new DateTime(scheduleOrderVo.getReserveDate()).toString("yyyy-MM-dd"));
        paramMap.put("reserveTime", scheduleOrderVo.getReserveTime());
        paramMap.put("amount", scheduleOrderVo.getAmount()); //挂号费用
        paramMap.put("name", patient.getName());
        paramMap.put("certificatesType", patient.getCertificatesType());
        paramMap.put("certificatesNo", patient.getCertificatesNo());
        paramMap.put("sex", patient.getSex());
        paramMap.put("birthdate", patient.getBirthdate());
        paramMap.put("phone", patient.getPhone());
        paramMap.put("isMarry", patient.getIsMarry());
        paramMap.put("provinceCode", patient.getProvinceCode());
        paramMap.put("cityCode", patient.getCityCode());
        paramMap.put("districtCode", patient.getDistrictCode());
        paramMap.put("address", patient.getAddress());
        paramMap.put("contactsName", patient.getContactsName());
        paramMap.put("contactsCertificatesType", patient.getContactsCertificatesType());
        paramMap.put("contactsCertificatesNo", patient.getContactsCertificatesNo());
        paramMap.put("contactsPhone", patient.getContactsPhone());
        paramMap.put("timestamp", HttpRequestHelper.getTimestamp());
        paramMap.put("sign", "");

        //4、调用医院端挂号接口--实现预约下达的操作
        JSONObject result = HttpRequestHelper.sendRequest(paramMap, "http://localhost:9998/order/submitOrder");

        //5、医院端返回值
        if (result.getInteger("code") == 200) { //挂号成功，取出医院端的返回数据

            JSONObject jsonObject = result.getJSONObject("data");//将返回值的JSON转为对象

            String hosRecordId = jsonObject.getString("hosRecordId");//医院端订单主键
            Integer number = jsonObject.getInteger("number");//预约序号
            String fetchTime = jsonObject.getString("fetchTime");//取号时间
            String fetchAddress = jsonObject.getString("fetchAddress");//取号地址

            //6、创建用户平台自己的订单
            OrderInfo orderInfo = new OrderInfo();

            BeanUtils.copyProperties(scheduleOrderVo, orderInfo);
            String outTradeNo = System.currentTimeMillis() + "" + new Random().nextInt(100);
            orderInfo.setOutTradeNo(outTradeNo);//订单的标号，支付和退款的时候使用
            orderInfo.setScheduleId(scheduleId);
            orderInfo.setUserId(patient.getUserId());
            orderInfo.setPatientId(patientId);
            orderInfo.setPatientName(patient.getName());
            orderInfo.setPatientPhone(patient.getPhone());
            orderInfo.setOrderStatus(OrderStatusEnum.UNPAID.getStatus());
            orderInfo.setHosRecordId(hosRecordId);
            orderInfo.setNumber(number);
            orderInfo.setFetchTime(fetchTime);
            orderInfo.setFetchAddress(fetchAddress);

            baseMapper.insert(orderInfo);//?????????????????????????????????????????????????

            //7、TODO（MQ） 发送mq消息，号源更新和短信通知  提高下单的并发性【提供者】
            //排班可预约数
            Integer reservedNumber = jsonObject.getInteger("reservedNumber");
            //排班剩余预约数
            Integer availableNumber = jsonObject.getInteger("availableNumber");


                this.afterSaveOrder(reservedNumber,availableNumber,scheduleId, orderInfo);
            //返回订单id
              return orderInfo.getId();
        } else {
            throw new YyghException(20001, "挂号失败");
        }
    }

    /**
     * @description:  根据订单id查询订单详情接口
     * @author 化一帆
     * @date 2022/12/8 21:09
     */
    @Override
    public OrderInfo getOrderInfo(Long id) {
        OrderInfo orderInfo = baseMapper.selectById(id);
        return this.packOrderInfo(orderInfo);
    }



    //私有方法
    private OrderInfo packOrderInfo(OrderInfo orderInfo) {
        orderInfo.getParam().put("orderStatusString", OrderStatusEnum.getStatusNameByStatus(orderInfo.getOrderStatus()));
        return orderInfo;
    }

    /**
     * @description:  调用rabbitmq发送消息
     * @author 化一帆
     * @date 2022/12/10 0:02
     */
    private void afterSaveOrder(Integer reservedNumber,Integer availableNumber,String scheduleId,OrderInfo orderInfo){

        //发送mq信息更新号源和短信通知
        OrderMqVo orderMqVo = new OrderMqVo();
        orderMqVo.setScheduleId(scheduleId);
        orderMqVo.setReservedNumber(reservedNumber);
        orderMqVo.setAvailableNumber(availableNumber);

        //短信提示
        MsmVo msmVo = new MsmVo();
        msmVo.setPhone(orderInfo.getPatientPhone());
        msmVo.getParam().put("message","挂号成功！");


        orderMqVo.setMsmVo(msmVo);

        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);
    }

    /**
     * @description:  订单列表接口【实现条件查询加分页】
     * @author 化一帆
     * @date 2022/12/9 19:13
     */

    @Override
    public IPage<OrderInfo> selectPage(Page<OrderInfo> pageParam, OrderQueryVo orderQueryVo) {
        //orderQueryVo获取条件值
        String name = orderQueryVo.getKeyword(); //医院名称
        Long patientId = orderQueryVo.getPatientId(); //就诊人名称
        String orderStatus = orderQueryVo.getOrderStatus(); //订单状态
        String reserveDate = orderQueryVo.getReserveDate();//安排时间
        String createTimeBegin = orderQueryVo.getCreateTimeBegin();
        String createTimeEnd = orderQueryVo.getCreateTimeEnd();
        Long userId = orderQueryVo.getUserId();

        //对条件值进行非空判断
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();

        if(!StringUtils.isEmpty(userId)) {
            wrapper.eq("user_id",userId);
        }
        if(!StringUtils.isEmpty(name)) {
            wrapper.like("hosname",name);
        }
        if(!StringUtils.isEmpty(patientId)) {
            wrapper.eq("patient_id",patientId);
        }
        if(!StringUtils.isEmpty(orderStatus)) {
            wrapper.eq("order_status",orderStatus);
        }
        if(!StringUtils.isEmpty(reserveDate)) {
            wrapper.ge("reserve_date",reserveDate);
        }
        if(!StringUtils.isEmpty(createTimeBegin)) {
            wrapper.ge("create_time",createTimeBegin);
        }
        if(!StringUtils.isEmpty(createTimeEnd)) {
            wrapper.le("create_time",createTimeEnd);
        }

        //调用mapper的方法
        IPage<OrderInfo> pages = baseMapper.selectPage(pageParam, wrapper);

        //编号变成对应值封装【将状态变成对应的值存放在orderinfo对象的param属性中，以便在前端进行文字显示】
        pages.getRecords().stream().forEach(item -> {
            this.packOrderInfo(item);
        });
        return pages;
    }

    /**
     * @description:  取消预约的接口
     * @author 化一帆
     * @date 2022/12/11 19:01
     */
    @Override
    public Boolean cancelOrder(Long orderId) {
        //查询到平台端的订单
        OrderInfo orderInfo = baseMapper.selectById(orderId);

        //判断是否退号时间已过
        Date quitTime = orderInfo.getQuitTime();
        DateTime dateTime = new DateTime(quitTime);
        if(dateTime.isBeforeNow()){
            throw new YyghException(20001,"退号时间已过");
//            return false;
        }

        //1、调用医院端的接口
        String url = "http://localhost:9998/order/updatePayStatus";

        Map<String,Object> map = new HashMap<>();
        map.put("hoscode",orderInfo.getHoscode());
        map.put("hosRecordId",orderInfo.getHosRecordId());
        JSONObject jsonObject = HttpRequestHelper.sendRequest(map, url);

        Integer code = jsonObject.getInteger("code");

        System.out.println(code);
        if(code!=200){
            throw new YyghException(20001,"医院端退款接口调用失败");
        }

        //2、判断订单状态
        Integer orderStatus = orderInfo.getOrderStatus();
        //根据支付记录的支付状态去判断，也可以
        if (orderStatus==OrderStatusEnum.PAID.getStatus()){//1-已支付
            //退款流程
            boolean bol = refundService.refund(orderId);//创建退款记录（先判断订单对应的退款记录是否存在）--》调用微信接口退款--》更新退款记录（4个字段）
            if(!bol){
                throw new YyghException(20001,"退款失败");
            }
        }

        //3、平台端的订单状态改成-1
        orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());
        baseMapper.updateById(orderInfo);

        //4、向第3个队列中发送消息【如果使用第一个队列发送消息，消费者监听需要根据orderMqVo的值来判断】
        OrderMqVo orderMqVo = new OrderMqVo();
        orderMqVo.setScheduleId(orderInfo.getScheduleId());//mg中排班id
//        orderMqVo.setAvailableNumber();
        String patientPhone = orderInfo.getPatientPhone();//就诊人手机号
        MsmVo msmVo = new MsmVo();
        msmVo.setPhone(patientPhone);
        msmVo.getParam().put("message","订单已取消！");
        orderMqVo.setMsmVo(msmVo);

        //向第三个队列发消息
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_CANCEL_ORDER,MqConst.ROUTING_CANCEL_ORDER,orderMqVo);
        //向第一个队列发消息
//        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,orderMqVo);

        return true;
    }
}